home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Games of Daze
/
Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso
/
x2ftp
/
msdos
/
mxutil
/
tspak17
/
do_rec.asm
< prev
next >
Wrap
Assembly Source File
|
1994-07-26
|
11KB
|
473 lines
; DO_REC.ASM
;
; External assembler subroutine for Recwav.pas, performs the actual record-
; ing of sound. Although this is to be assembled to an .obj file, it is
; almost a .com file in its own right. This routine assumes the DAC has
; already been initialized.
;
CODE SEGMENT BYTE PUBLIC
ASSUME CS:CODE,DS:CODE
PUBLIC DO_REC
DO_REC PROC NEAR
JMP START
;
; Stack frame structure.
;
STACKFRAME STRUC [BP]
OLDBP DW ? ; caller's BP
RETADDR DW ? ; return address
ASCZFILE DD ? ; pointer to ASCIIZ filename of output file
BUFFER1 DD ? ; pointer to DMA buffer 1
BUFFER0 DD ? ; pointer to DMA buffer 0
INRATE DW ? ; input sampling rate in Hz, for .wav header
DIVIDER DW ? ; divider for Int 1Ah function 82h
ENDS
;
; Return codes.
;
RECOK EQU 0 ; recording successful
DISKERR EQU 1 ; disk I/O error
FULLDISK EQU 2 ; disk full
OVERFLOW EQU 3 ; input overflow (sampling rate too fast)
OPENFAIL EQU 4 ; open failed on output file
WORKING EQU 5 ; sound input in progress (not a return code)
;
; Local data. First, copies of parameters (easier to get at,
; particularly from inside an interrupt handler).
;
ASCZFILE_L DD 0 ; local copy of parameter ASCZFILE
BUFFERPTRS LABEL DWORD ; buffer pointers, as array[0..1] of dword
BUFFER0_L DD 0 ; local copy of parameter BUFFER0
BUFFER1_L DD 0 ; local copy of parameter BUFFER1
DIVIDER_L DW 0 ; local copy of parameter DIVIDER
EVENT DW WORKING ; event status (return code)
CURRENTOUT DW 0 ; current output buffer (0 or 1)
CURRENTIN DW 0 ; current input buffer (0 or 1)
FULLBUFFER DB 0,0 ; buffer full flags, 1 = full
LASTBUFFER DB 0,0 ; last buffer flags, 1 = final buffer
STOPNOW DB 0 ; 1 = recording should stop
RECSTOPPED DB 0 ; 1 = sound recording stopped
KEYPRESSED DB 0 ; key pressed flag, 1 = key has been pressed
HANDLE DW 0 ; file handle of output file
FILELEN DD 0 ; length of the output file
STARTPROMPT DB "Press a key to begin recording.",0Dh,0Ah,"$"
STOPPROMPT DB "Press a key to stop recording.",0Dh,0Ah,"$"
INT15VEC DD 0 ; default Int 15h vector
;
; RIFF WAVE header template, for writing to the output file.
; 44 bytes long. OUTRATE1 and OUTRATE2 should be filled in
; before the template is written out. After recording is
; done, the dword at offset 4 should be filled in with the
; length of the output file minus 8, and the dword at offset
; 40 should be filled in with the length of the output file
; minus 44.
;
TEMPLATE LABEL BYTE
DB 'RIFF' ; RIFF header
RIFFSIZE DD 0 ; (length of output file) - 8 goes here
DB 'WAVEfmt ' ; WAVE header and format chunk label
DD 16 ; format chunk length
DW 1 ; Microsoft PCM format tag
DW 1 ; mono
OUTRATE1 DW 0 ; fill in with sampling rate
DW 0
OUTRATE2 DW 0 ; fill in sampling rate here too
DW 0
DW 1 ; bytes per sample
DW 8 ; bits per sample
DB 'data'
DATASIZE DD 0 ; (length of output file) - 44 goes here
;
; Replacement Int 15h handler. This is actually 2 Int 15h
; handlers in one: the first part handles Int 15h function
; 4Fh, the keyboard intercept, setting the KEYPRESSED flag
; above and telling the BIOS to ignore the keystroke; the
; second part handles Int 15h, AX=91FBh, the BIOS callout
; for sound chip DMA EOP.
;
; First part: keyboard intercept. Set KEYPRESSED flag (if
; it's a make code) and tell the BIOS to ignore the keystroke.
;
INT15HDLR: CMP AH,4Fh
JNE I15_NOTKEY
NOT AL ; 1 in bit 7 = make code
ROL AL,1 ; 1 in bit 0 = make code
AND AL,1 ; zero out other bits
OR CS:KEYPRESSED,AL ; set if make code
CLC
RETF 2
;
; If not keyboard intercept, and not DMA EOP, then jump to
; default handler.
;
I15_NOTKEY: CMP AX,91FBh
JE I15_DMAEOP
JMP DWORD PTR CS:INT15VEC
;
; DMA end-of-process occurred on sound input. DS addresses
; local data.
;
I15_DMAEOP: PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH DS
PUSH ES
PUSH CS
POP DS
;
; Check first if STOPNOW flag is set; if so, stop. (The main
; program sets this flag in case of disk errors.)
;
CMP STOPNOW,1
JNE NOTSTOPNOW
MOV RECSTOPPED,1
JMP I15_END
;
; STOPNOW flag not set. Mark the current buffer full. If a
; keystroke has occurred, mark the current buffer last and
; stop.
;
NOTSTOPNOW: MOV BX,CURRENTIN
MOV FULLBUFFER[BX],1
CMP KEYPRESSED,1
JNE NOKEYYET
MOV RECSTOPPED,1
MOV LASTBUFFER[BX],1
JMP I15_END
;
; No keypress yet. Switch input buffers.
;
NOKEYYET: XOR BX,1
MOV CURRENTIN,BX
;
; If the new current input buffer is still marked full,
; overflow has occurred.
;
CMP FULLBUFFER[BX],1
JNE NOOVERFLOW
MOV RECSTOPPED,1
MOV EVENT,OVERFLOW
JMP I15_END
;
; Buffer is empty. Fill it.
;
NOOVERFLOW: MOV AH,82h
SHL BX,1
SHL BX,1
LES BX,BUFFERPTRS[BX]
MOV CX,32768
MOV DX,DIVIDER_L
INT 1Ah
I15_END: POP ES
POP DS
POP DX
POP CX
POP BX
POP AX
IRET
;
; Subroutine, opens the output file. Returns: carry set if
; error, file handle in AX otherwise.
;
OPENFILE: PUSH CX
PUSH DX
PUSH DS
MOV AH,3Ch
XOR CX,CX
LDS DX,ASCZFILE_L
INT 21h
POP DS
POP DX
POP CX
RET
;
; Subroutine, closes the output file and flushes the disk
; buffers. Returns nothing.
;
CLOSEFILE: PUSH AX
PUSH BX
MOV AH,3Eh
MOV BX,HANDLE
INT 21h
MOV AH,0Dh
INT 21h
POP BX
POP AX
RET
;
; Subroutine, erases the output file.
;
ERASEFILE: PUSH AX
PUSH DX
PUSH DS
MOV AH,41h
LDS DX,ASCZFILE_L
INT 21h
POP DS
POP DX
POP AX
RET
;
; Subroutine, starts sound recording.
;
STARTRECORD: PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH ES
MOV AH,82h
LES BX,BUFFER0_L
MOV CX,32768
MOV DX,DIVIDER_L
INT 1Ah
POP ES
POP DX
POP CX
POP BX
POP AX
RET
;
; Subroutine, stops sound recording. Waits for the recording
; process to indicate that it has stopped.
;
STOPRECORD: MOV STOPNOW,1
L0: CMP RECSTOPPED,1
JNE L0
RET
;
; Main routine. BP addresses the stack frame; DS addresses
; the code segment.
;
START: PUSH BP
MOV BP,SP
PUSH DS
PUSH CS
POP DS
;
; Create local copies of parameters.
;
MOV AX,DIVIDER
MOV DIVIDER_L,AX
MOV AX,INRATE ; fill in header template
MOV OUTRATE1,AX
MOV OUTRATE2,AX
LES AX,BUFFER0
MOV WORD PTR BUFFER0_L,AX
MOV WORD PTR BUFFER0_L+2,ES
LES AX,BUFFER1
MOV WORD PTR BUFFER1_L,AX
MOV WORD PTR BUFFER1_L+2,ES
LES AX,ASCZFILE
MOV WORD PTR ASCZFILE_L,AX
MOV WORD PTR ASCZFILE_L+2,ES
;
; Open the output file.
;
CALL OPENFILE
JNC OPEN_SUCCESS
;
; Open failed. Set event code and jump to end.
;
MOV EVENT,OPENFAIL
JMP MAIN_EXIT
;
; Open succeeded. Save handle and write .wav header.
;
OPEN_SUCCESS: MOV HANDLE,AX
MOV BX,AX
MOV AH,40h
MOV CX,44
MOV DX,OFFSET TEMPLATE
INT 21h
JC HDR_FAIL
CMP AX,CX
JE HDR_SUCCESS
;
; Error writing to disk. Close the output file and delete it,
; set event code to DISKERR, and jump to exit.
;
HDR_FAIL: CALL CLOSEFILE
CALL ERASEFILE
MOV EVENT,DISKERR
JMP MAIN_EXIT
;
; Header successfully written out. Display starting prompt
; to the user.
;
HDR_SUCCESS: MOV AH,9
MOV DX,OFFSET STARTPROMPT
INT 21h
;
; Flush the keyboard buffer.
;
KEYBUF_FLUSH: MOV AH,1
INT 16h
JZ KEYBUF_EMPTY
MOV AH,0
INT 16h
JMP KEYBUF_FLUSH
;
; Keyboard buffer empty. Wait for a keystroke.
;
KEYBUF_EMPTY: MOV AH,0
INT 16h
;
; Display stopping prompt to the user.
;
MOV AH,9
MOV DX,OFFSET STOPPROMPT
INT 21h
;
; Hook Int 15h.
;
MOV AX,3515h
INT 21h
MOV WORD PTR INT15VEC,BX
MOV WORD PTR INT15VEC+2,ES
MOV AX,2515h
MOV DX,OFFSET INT15HDLR
INT 21h
;
; Start recording.
;
CALL STARTRECORD
;
; **** Main output loop. If overflow has occurred, close
; and delete the output file and exit the program.
;
MAINLOOP: CMP EVENT,OVERFLOW
JNE NO_OVERFLOW
CALL CLOSEFILE
CALL ERASEFILE
JMP UNHOOK
;
; No overflow. See if the current output buffer is full yet.
; If not, keep checking for overflow or a full buffer.
;
NO_OVERFLOW: MOV SI,CURRENTOUT
CMP FULLBUFFER[SI],1
JNE MAINLOOP
;
; Write the buffer to disk.
;
PUSH DS
MOV AH,40h
MOV BX,HANDLE
MOV CX,32768
SHL SI,1
SHL SI,1
LDS DX,BUFFERPTRS[SI]
INT 21h
POP DS
;
; If disk error, stop recording, close and delete the output
; file, set the return code to DISKERR, and exit.
;
JNC BUFFERDONE
CALL STOPRECORD
CALL CLOSEFILE
CALL ERASEFILE
MOV EVENT,DISKERR
JMP UNHOOK
;
; If full disk, stop recording, set return code to FULLDISK,
; and go set the file size in the .wav header.
;
BUFFERDONE: CMP AX,CX
JE NOTFULL
CALL STOPRECORD
MOV EVENT,FULLDISK
JMP SETSIZE
;
; Disk not full. If this was the last output buffer, exit
; the loop (recording already stopped).
;
NOTFULL: MOV BX,CURRENTOUT
CMP LASTBUFFER[BX],1
JE MAIN_LPEND
;
; Not the last output buffer. Mark the current output buffer
; empty, switch buffers, and go to the top of the loop to wait
; for more output.
;
MOV FULLBUFFER[BX],0
XOR CURRENTOUT,1
JMP MAINLOOP
;
; Recording successful.
;
MAIN_LPEND: MOV EVENT,RECOK
;
; Set the size fields in the .wav header. First, get the
; length of the file from DOS.
;
SETSIZE: MOV AX,4202h
MOV BX,HANDLE
XOR CX,CX
MOV DX,CX
INT 21h
JC SIZEERROR
;
; Fill in the size fields in the .wav header template.
;
SUB AX,8
SBB DX,0
MOV WORD PTR RIFFSIZE,AX
MOV WORD PTR RIFFSIZE+2,DX
SUB AX,36
SBB DX,0
MOV WORD PTR DATASIZE,AX
MOV WORD PTR DATASIZE+2,DX
;
; Seek to the beginning of the file and write out the header
; template again.
;
MOV AX,4200h
MOV BX,HANDLE
XOR CX,CX
MOV DX,CX
INT 21h
JC SIZEERROR
MOV AH,40h
MOV BX,HANDLE
MOV CX,44
MOV DX,OFFSET TEMPLATE
INT 21h
JC SIZEERROR
CMP AX,CX
JNE SIZEERROR
;
; Close the output file and exit.
;
CALL CLOSEFILE
JMP UNHOOK
;
; File error occurred while setting the size fields in the
; .wav header, or when closing the file. Close the file
; (if not closed already) and delete it, then set the return
; code to DISKERR.
;
SIZEERROR: CALL CLOSEFILE
CALL ERASEFILE
MOV EVENT,DISKERR
;
; Unhook Int 15h.
;
UNHOOK: PUSH DS
MOV AX,2515h
LDS DX,INT15VEC
INT 21h
POP DS
;
; Set return code, restore registers and exit.
;
MAIN_EXIT: MOV AX,EVENT
POP DS
POP BP
RET 16 ; discard parameters
DO_REC ENDP
CODE ENDS
END